﻿using System;
//4.11.11 不可调用的函数
//有一些函数是不能够动态调用的。如下：
//    扩展方法（通过扩展方法语法）
//    接口的所有成员
//    子类隐藏的基类成员
//理解这其中的原因对于理解动态绑定是非常有用的。

//动态绑定包含两部分信息：调用的函数名和调用该函数的对象。然而，在这三种不可调用的情况下，还涉及到一个附加类型，它只在编译时可见。在C#5.0中，我们是无法动态指定这类附加类型的。

//在调用扩展方法时，它的附加类型时隐式的，这是扩展方法定义所在的静态类。编译器会根据源代码中的using指令来搜索这个类。这使得扩展方法成为只适用于编译时的概念，因为using指令在编译后消失（当它们在绑定过程中完成了将简单的名称映射到完整命名空间名称的任务之后）。

//当通过接口调用成员时，需要通过一个隐式或显式的转换来指定这个附加类型。
//有两种情况需要执行这个操作：调用显式实现的接口和调用另一程序集内部类型中实现的接口成员。
//我们可以通过下面两种类型来演示前一种情况：
interface IFoo { void Test(); }
class Foo : IFoo { void IFoo.Test() { } }

namespace _137_动态绑定_不可调用的函数
{
    class Program
    {
        static void Main(string[] args)
        {
            // 如果要调用Test方法，我们必须将它转换为IFoo接口。这种情况通过静态方式实现是最简单的：
            /*
            IFoo f = new Foo(); // 隐式转换为接口
            f.Test();
            */
            //下面是动态类型转换的例子：
            IFoo f = new Foo();
            dynamic d = f;
            //d.Test();  //抛出异常
            //粗体字显式的隐式转换是告诉编译器将f的后续成员绑定到IFoo上，而不是绑定到Foo上——换句话说，要通过IFoo接口的视角来查看该对象。然而，这个视角在运行时会消失，所以DLR无法完成这个绑定过程。整个消失过程如下所示：
            Console.WriteLine(f.GetType().Name); // Foo
            //类似的情况也出现在调用隐藏的基类成员上：必须通过强制转换成base关键字来指定一个附加类型，否则附加类型会在运行时丢失。

            Console.ReadKey();
        }
    }
}
